package com.pandora.common.check;

import java.io.StringReader;

import javax.servlet.http.HttpServletRequest;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.alibaba.fastjson.JSONObject;
import com.pandora.common.exception.EduException;
import com.pandora.common.util.CommonUtils;
import com.pandora.common.util.StringUtils;
import com.pandora.common.util.WebUtils;
import com.pandora.framework.constant.ResponseConstants;
import com.pandora.framework.constant.ServiceConstants;
import com.pandora.framework.util.LogUtils;
import com.pandora.framework.util.PropertiesUtils;
import com.pandora.framework.util.ServiceConfigUtils;
import com.pandora.framework.util.ServiceUtils;
import com.pandora.framework.vo.ServiceConfigVO;
import com.pandora.framework.vo.ServiceCoreVO;

/**
 * 系统服务接口工具类
 * 
 * @author JingChenglong 2017/12/20 21:08
 *
 */
public class APIContentChecks {

	private ServiceCoreVO serviceCoreVO;// 请求体
	private ServiceConfigVO configVO;// 本地接口服务

	private HttpServletRequest request;
	private boolean upFlag;// 是否为上传接口

	public static APIContentChecks getInstance(ServiceCoreVO serviceCoreVO, HttpServletRequest request) {

		APIContentChecks apiChk = new APIContentChecks();
		apiChk.serviceCoreVO = serviceCoreVO;
		apiChk.request = request;
		apiChk.upFlag = StringUtils.isNotEmpty(serviceCoreVO.getAction());

		return apiChk;
	}

	public ServiceConfigVO checkContent() throws EduException {

		checkAction();// 校验action
		setRequestContent();// 设置请求数据
		checkRequestType();// 校验请求类型
		getServiceConfig();// 获取接口服务对象
		ConfigChecks.checkIp(configVO.getIp(), serviceCoreVO.getIp());// 校验IP
		ConfigChecks.checkStatus(configVO.getStatus());// 校验接口状态
		checkRequestTime();// 超时校验
		ConfigChecks.checkServiceType(configVO.getServiceType(), serviceCoreVO.getServiceType());// 接口服务类型校验
		checkAccessId();// 校验通行证ID

		if (upFlag) {
			// TODO 上传文件时校验文件长度
		} else {
			// 非上传文件时校验签名
			if (ServiceConstants.SERVICE_SIGNTYPE_MD5.equals(configVO.getSignType())) {
				ConfigChecks.checkSignMD5(serviceCoreVO.getReqcontentmd5(), serviceCoreVO.getSign());
			} else if (ServiceConstants.SERVICE_SIGNTYPE_HMACSHA1.equalsIgnoreCase(configVO.getSignType())) {
				ConfigChecks.checkSignHMACSHA1(serviceCoreVO.getAccesskey(), serviceCoreVO.getReqcontentmd5(),
						serviceCoreVO.getSign());
			} else {
				throw new EduException(ResponseConstants.SIGN_TYPE_ERROR);
			}
		}

		return configVO;
	}

	/** 校验请求类型 */
	private void checkRequestType() throws EduException {

		String requestType = "";
		if (!upFlag) {
			requestType = ServiceUtils.getRequestContentValue(serviceCoreVO.getReqObject(),
					ServiceConstants.REQUEST_TYPE);
		} else {
			requestType = WebUtils.getHeaderDecode(request, ServiceConstants.REQUEST_TYPE);
		}

		serviceCoreVO.setRequestType(requestType);
	}

	/** 设置请求数据 */
	private void setRequestContent() throws EduException {

		Object reqObject = null;

		if (!upFlag) {
			try {
				if (ServiceConstants.XML.equalsIgnoreCase(serviceCoreVO.getFormat())) {
					reqObject = getRootXML().attribute(ServiceConstants.CONTENT);
				} else if (ServiceConstants.JSON.equalsIgnoreCase(serviceCoreVO.getFormat())) {
					reqObject = getRootJSON().get(ServiceConstants.CONTENT);
				} else {
					throw new EduException(ResponseConstants.REQUEST_CONTENT_FORMAT_ERROR);
				}
			} catch (Exception e) {
				LogUtils.logError(CommonUtils.getTraceInfo() + e.getMessage());
			}

		} else {
			serviceCoreVO.setRequest(request);
		}

		serviceCoreVO.setReqObject(reqObject);
	}

	/** 超时校验 */
	private void checkRequestTime() throws EduException {

		String reqTime = "";

		if (upFlag) {
			reqTime = WebUtils.getHeaderDecode(request, ServiceConstants.REQTIME);
		} else {
			try {
				if (ServiceConstants.XML.equalsIgnoreCase(serviceCoreVO.getFormat())) {
					reqTime = StringUtils.nullToStrTrim(getCommonXML().attributeValue(ServiceConstants.REQTIME));
				} else if (ServiceConstants.JSON.equalsIgnoreCase(serviceCoreVO.getFormat())) {
					reqTime = StringUtils.nullToStrTrim(getCommonJSON().getString(ServiceConstants.REQTIME));
				} else {
					throw new EduException(ResponseConstants.REQUEST_CONTENT_FORMAT_ERROR);
				}
			} catch (Exception e) {
				LogUtils.logError(CommonUtils.getTraceInfo() + e.getMessage());
				reqTime = "";
			}
		}

		serviceCoreVO.setRequestTime(reqTime);

		ConfigChecks.checkTimeOut(reqTime, configVO.getTimeout());
	}

	/** 校验通行证ID */
	private void checkAccessId() throws EduException {

		if (StringUtils.isEmpty(configVO.getAccessIdFlag())
				|| ServiceConstants.ACCESS_FLAG_FALSE.equalsIgnoreCase(configVO.getAccessIdFlag())) {
			return;
		}

		String accessId = "";

		if (upFlag) {
			accessId = WebUtils.getHeaderDecode(request, ServiceConstants.ACCESSID);
		} else {
			accessId = StringUtils.nullToStrTrim(
					ServiceUtils.getRequestContentValue(serviceCoreVO.getReqObject(), ServiceConstants.ACCESSID));
		}

		ConfigChecks.checkAccessId(accessId);

		String requestType = serviceCoreVO.getRequestType();

		if (StringUtils.isEmpty(requestType)) {
			throw new EduException(ResponseConstants.REQUEST_TYPE_ISNULL);
		}

		if ("pay".equals(configVO.getType())) {
			if (!accessId.equals(
					PropertiesUtils.getAccess(configVO.getType().toUpperCase() + ServiceConstants._ACCESS_ID))) {
				throw new EduException(ResponseConstants.ACCESSID_INVALID);
			}
			serviceCoreVO.setAccessid(accessId);
			serviceCoreVO.setAccesskey(
					PropertiesUtils.getAccess(configVO.getType().toUpperCase() + ServiceConstants._ACCESS_KEY));
		} else {
			if (!accessId.equals(
					PropertiesUtils.getAccess(configVO.getType().toUpperCase() + ServiceConstants._ACCESS_ID))) {
				throw new EduException(ResponseConstants.ACCESSID_INVALID);
			}
			serviceCoreVO.setAccessid(accessId);
			serviceCoreVO.setAccesskey(configVO.getAccessKeyValue());
		}
	}

	/** 校验action */
	private void checkAction() throws EduException {

		if (upFlag) {
			return;
		}

		String action = "";

		if (ServiceConstants.XML.equalsIgnoreCase(serviceCoreVO.getFormat())) {
			action = StringUtils.nullToStrTrim(getCommonXML().elementTextTrim(ServiceConstants.ACTION));
		} else if (ServiceConstants.JSON.equalsIgnoreCase(serviceCoreVO.getFormat())) {
			action = StringUtils.nullToStrTrim(getCommonJSON().getString(ServiceConstants.ACTION));
		} else {
			throw new EduException(ResponseConstants.REQUEST_CONTENT_FORMAT_ERROR);
		}

		if (StringUtils.isEmpty(action)) {
			throw new EduException(ResponseConstants.ACTION_CANNOT_BENULL);
		}

		serviceCoreVO.setAction(action);
	}

	/** 获取接口服务对象 */
	public void getServiceConfig() throws EduException {

		configVO = ServiceConfigUtils.getServiceConfig(serviceCoreVO.getAction());

		if (configVO.getUpFlag().equals(ServiceConstants.UP_FLAG_TRUE) && !upFlag) {
			throw new EduException(ResponseConstants.SERVICE_ASCMETHOD_ERROR);
		}

		if (!configVO.getType().equalsIgnoreCase(serviceCoreVO.getRequestType())) {
			throw new EduException(ResponseConstants.REQUEST_TYPE_ERROR);
		}

		serviceCoreVO.setType(configVO.getType());
	}

	/** 读取XML格式的请求体中common中的请求信息 */
	private Element getCommonXML() throws EduException {

		Element commonXML = getRootXML().element(ServiceConstants.COMMON);

		if (commonXML == null) {
			throw new EduException(ResponseConstants.REQUEST_CONTENT_ERROR);
		}

		return commonXML;
	}

	/** 读取JSON格式的请求体中common中的请求信息 */
	public JSONObject getCommonJSON() throws EduException {

		JSONObject commonJSON = getRootJSON().getJSONObject(ServiceConstants.COMMON);

		if (commonJSON == null) {
			throw new EduException(ResponseConstants.REQUEST_CONTENT_ERROR);
		}

		return commonJSON;
	}

	/** 从XML格式的请求体中读取请求体内容信息 */
	private Element getRootXML() throws EduException {

		StringReader reader = new StringReader(serviceCoreVO.getReqContent());

		Document doc = null;

		try {
			doc = new SAXReader().read(reader);
		} catch (Exception e) {
			LogUtils.logError(CommonUtils.getTraceInfo() + e.getMessage());
			throw new EduException(ResponseConstants.REQUEST_CONTENT_ERROR);
		}

		Element rootXML = doc.getRootElement();

		if (rootXML == null) {
			throw new EduException(ResponseConstants.REQUEST_CONTENT_ERROR);
		}

		return rootXML;
	}

	/** 从JSON格式的请求体重读取请求体内容信息 */
	private JSONObject getRootJSON() throws EduException {

		JSONObject json = JSONObject.parseObject(serviceCoreVO.getReqContent());

		try {
			if (json == null) {
				throw new EduException(ResponseConstants.REQUEST_CONTENT_ERROR);
			}

			json = json.getJSONObject(ServiceConstants.REQUEST_ROOT);
			if (json == null) {
				throw new EduException(ResponseConstants.REQUEST_CONTENT_ERROR);
			}
		} catch (Exception e) {
			LogUtils.logError(CommonUtils.getTraceInfo() + e.getMessage());
			throw new EduException(ResponseConstants.REQUEST_CONTENT_ERROR);
		}

		return json;
	}
}